package com.huangfuyi.datasource.factory;

import com.huangfuyi.common.utils.ObjectUtils;
import com.huangfuyi.datasource.entity.EConnectConf;
import com.huangfuyi.datasource.entity.EDataDefineConf;
import com.huangfuyi.datasource.enums.EDataSourceType;
import com.huangfuyi.datasource.exceptions.EDataSourceInitException;
import com.huangfuyi.datasource.exceptions.EDataSourceNoSuchImpException;
import com.huangfuyi.datasource.service.EDataSource;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * 持久层工厂，用于获取各种数据源链接
 */
public class EDataSourceFactory {

    // 获取数据源链接
    public static EDataSource getDataSource(EDataSourceType type, List<EConnectConf> connectInfo) {
        Class<?> dataSourceClass;
        try {
            dataSourceClass = Class.forName(type.getFullClassName());
            if (ObjectUtils.isEmpty(dataSourceClass)) {
                throw new EDataSourceNoSuchImpException("获取数据源实现失败");
            }
        } catch (Throwable e) {
            throw new EDataSourceNoSuchImpException(String.format(Locale.ROOT, "当前项目没有引入（%s）数据源依赖", type.getLabel()));
        }

        try {
            Constructor<?> constructor = dataSourceClass.getConstructor();
            Object dataSourceObj = constructor.newInstance();
            if (ObjectUtils.isEmpty(dataSourceObj)) {
                throw new EDataSourceInitException("数据源实例化失败。");
            }
            EDataSource dataSource;
            if (dataSourceObj instanceof EDataSource) {
                dataSource = (EDataSource) dataSourceObj;
            } else {
                throw new EDataSourceInitException("非法的数据源实现。");
            }
            dataSource.init(connectInfo);
            return dataSource;
        } catch (Throwable e) {
            throw new EDataSourceInitException(String.format(Locale.ROOT, "数据源（%s）实例化失败，失败原因：%s", type.getLabel(), e.getMessage()));
        }
    }

    public static List<EConnectConf> map2ConnectConfig(EDataSourceType type, List<Map<String, Object>> connectInfo) {
        Class<?> dataSourceClass = null;
        try {
            dataSourceClass = Class.forName(type.getFullClassName());
            if (ObjectUtils.isEmpty(dataSourceClass)) {
                throw new EDataSourceNoSuchImpException("获取数据源实现失败");
            }
        } catch (Throwable e) {
            throw new EDataSourceNoSuchImpException(String.format(Locale.ROOT, "当前项目没有引入（%s）数据源依赖", type.getLabel()));
        }

        try {
            Constructor<?> constructor = dataSourceClass.getConstructor();
            Object dataSourceObj = constructor.newInstance();
            if (ObjectUtils.isEmpty(dataSourceObj)) {
                throw new EDataSourceInitException("数据源实例化失败。");
            }

            EDataSource dataSource;
            if (dataSourceObj instanceof EDataSource) {
                dataSource = (EDataSource) dataSourceObj;
            } else {
                throw new EDataSourceInitException("非法的数据源实现。");
            }

            Class<? extends EConnectConf> connectInfoExample = dataSource.getConnectInfoExample();
            Constructor<? extends EConnectConf> connectInfoConstructor = connectInfoExample.getConstructor();

            ArrayList<EConnectConf> result = new ArrayList<>();
            Field[] fields = connectInfoExample.getDeclaredFields();
            for (Map<String, Object> connectInfoMapElem : connectInfo) {
                EConnectConf connectConf = connectInfoConstructor.newInstance();

                for (Field field : fields) {
                    field.set(connectConf, connectInfoMapElem.get(field.getName()));
                }
                result.add(connectConf);
            }
            return result;
        } catch (Throwable e) {
            throw new EDataSourceInitException(String.format(Locale.ROOT, "数据源（%s）实例化失败，失败原因：%s", type.getLabel(), e.getMessage()));
        }
    }

    public static Class<? extends EConnectConf> getConnectInfoExample(EDataSourceType type){
        Class<?> dataSourceClass = null;
        try {
            dataSourceClass = Class.forName(type.getFullClassName());
            if (ObjectUtils.isEmpty(dataSourceClass)) {
                throw new EDataSourceNoSuchImpException("获取数据源实现失败");
            }
        } catch (Throwable e) {
            throw new EDataSourceNoSuchImpException(String.format(Locale.ROOT, "当前项目没有引入（%s）数据源依赖", type.getLabel()));
        }

        try {
            Constructor<?> constructor = dataSourceClass.getConstructor();
            Object dataSourceObj = constructor.newInstance();
            if (ObjectUtils.isEmpty(dataSourceObj)) {
                throw new EDataSourceInitException("数据源实例化失败。");
            }

            EDataSource dataSource;
            if (dataSourceObj instanceof EDataSource) {
                dataSource = (EDataSource) dataSourceObj;
            } else {
                throw new EDataSourceInitException("非法的数据源实现。");
            }
            return dataSource.getConnectInfoExample();
        } catch (Throwable e) {
            throw new EDataSourceInitException(String.format(Locale.ROOT, "数据源（%s）获取链接信息配置样例失败，失败原因：%s", type.getLabel(), e.getMessage()));
        }

    }

    public static Class<? extends EDataDefineConf> getDataModelExample(EDataSourceType type){
        Class<?> dataSourceClass = null;
        try {
            dataSourceClass = Class.forName(type.getFullClassName());
            if (ObjectUtils.isEmpty(dataSourceClass)) {
                throw new EDataSourceNoSuchImpException("获取数据源实现失败");
            }
        } catch (Throwable e) {
            throw new EDataSourceNoSuchImpException(String.format(Locale.ROOT, "当前项目没有引入（%s）数据源依赖", type.getLabel()));
        }

        try {
            Constructor<?> constructor = dataSourceClass.getConstructor();
            Object dataSourceObj = constructor.newInstance();
            if (ObjectUtils.isEmpty(dataSourceObj)) {
                throw new EDataSourceInitException("数据源实例化失败。");
            }

            EDataSource dataSource;
            if (dataSourceObj instanceof EDataSource) {
                dataSource = (EDataSource) dataSourceObj;
            } else {
                throw new EDataSourceInitException("非法的数据源实现。");
            }
            return dataSource.getDataDefineInfoExample();
        } catch (Throwable e) {
            throw new EDataSourceInitException(String.format(Locale.ROOT, "数据源（%s）获取链接信息配置样例失败，失败原因：%s", type.getLabel(), e.getMessage()));
        }

    }
}
